/**************************************************************************************************
**                                                                                               **
**  文件名称:  dal_flash_drv.c                                                                   **
**  版权所有:  CopyRight @ Xiamen Yaxon NetWork CO.LTD. 2017                                     **
**  文件描述:  FLASH存储器读写的驱动管理                                                         **
**  ===========================================================================================  **
**  创建信息:  | 2017-3-20 | LEON | 创建本模块                                                   **
**  ===========================================================================================  **
**  修改信息:  单击此处添加....                                                                  **
**************************************************************************************************/
#include "dal_include.h"
#include "dal_flash_drv.h"

/**************************************************************************************************
**  函数名称:  DAL_Flash_Unlock
**  功能描述:  解锁FLASH擦除控制器
**  输入参数:  None
**  返回参数:  None
**************************************************************************************************/
void DAL_Flash_Unlock(void)
{
    FLASH_Unlock();
}

/**************************************************************************************************
**  函数名称:  DAL_Flash_Lock
**  功能描述:  锁定FLASH擦除控制器
**  输入参数:  None
**  返回参数:  None
**************************************************************************************************/
void DAL_Flash_Lock(void)
{
    FLASH_Lock();
}

/**************************************************************************************************
**  函数名称:  DAL_Flash_EraseOnePage
**  功能描述:  擦除FLASH页面
**  输入参数:  page: 页面编号, 从0开始
**  输出参数:  无
**  返回参数:  成功返回TRUE, 失败返回FALSE
**************************************************************************************************/
BOOLEAN DAL_Flash_EraseOnePage(INT8U page)
{
    INT32U addr;
    
    if (page >= PAGE_MAX_PAGE) {
        return FALSE;
    }
    
    addr = DAL_Flash_GetAddrByPage(page, TRUE);
    
    if (FLASH_COMPLETE != FLASH_ErasePage(addr)) {
        return FALSE;
    } else {
        return TRUE;
    }
}

/**************************************************************************************************
**  函数名称:  DAL_Flash_EraseSomePages
**  功能描述:  擦除连续的多个页面
**  输入参数:  无
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
BOOLEAN DAL_Flash_EraseSomePages(INT8U bpage, INT8U epage)
{
    INT8U   i;
    INT32U  addr;
    
    if (bpage >= epage) {
        return FALSE;
    }
    
    if ((bpage >= PAGE_MAX_PAGE) || (epage >= PAGE_MAX_PAGE)) {
        return FALSE;
    }
    
    for (i = bpage; i <= epage; i++) {
        
        addr = DAL_Flash_GetAddrByPage(i, TRUE);
        
        if (FLASH_COMPLETE != FLASH_ErasePage(addr)) {
            return FALSE;
        }
    }
    
    return TRUE;
}


/**************************************************************************************************
**  函数名称:  DAL_Flash_EraseAllPage
**  功能描述:  擦除所有FLASH页面
**  输入参数:  无
**  输出参数:  无
**  返回参数:  成功返回TRUE, 失败返回FALSE
**************************************************************************************************/
BOOLEAN DAL_Flash_EraseAllPage(void)
{
    if (FLASH_COMPLETE != FLASH_EraseAllPages()) {
        return FALSE;
    } else {
        return TRUE;
    }
}

/**************************************************************************************************
**  函数名称:  DAL_Flash_WriteHalfWord
**  功能描述:  写入一个16位数据(小端模式)
**  输入参数:  addr: 写入的地址, 绝对地址，2的整数倍，从0开始; data: 写入的数据
**  输出参数:  无
**  返回参数:  成功返回TRUE,失败返回FALSE
**************************************************************************************************/
BOOLEAN DAL_Flash_WriteHalfWord(INT32U addr, INT16U data)
{
    if (addr + 2 > ADDR_FLSH_END) {
        return FALSE;
    }
    
    if ((addr % 2) != 0) {
        return FALSE;
    }
    
    if (FLASH_COMPLETE != FLASH_ProgramHalfWord(addr, data)) {
        return FALSE;
    } else {
        if (*(volatile INT16U *)addr == data) {
            return TRUE;
        } else {
            return FALSE;
        }
    }
}

/**************************************************************************************************
**  函数名称:  DAL_Flash_WriteWord
**  功能描述:  写入一个32位数据(小端模式)
**  输入参数:  addr: 写入的地址, 绝对地址，2的整数倍，从0开始; data: 写入的数据
**  输出参数:  无
**  返回参数:  成功返回TRUE, 失败返回FALSE
**************************************************************************************************/
BOOLEAN DAL_Flash_WriteWord(INT32U addr, INT32U data)
{
    if (addr + 4 > ADDR_FLSH_END) {
        return FALSE;
    }
    
    if ((addr % 2) != 0) {
        return FALSE;
    }
    
    if (FLASH_COMPLETE != FLASH_ProgramWord(addr, data)) {
        return FALSE;
    } else {
        if (*(volatile INT32U *)addr == data) {
            return TRUE;
        } else {
            return FALSE;
        }
    }
}

/**************************************************************************************************
**  函数名称:  Flash_WriteData
**  功能描述:  写入一串数据，绝对地址，2的整数倍，从0开始
**  输入参数:  addr: 写入的地址, 绝对地址，2的整数倍，从0开始; data: 写入的数据; dlen: 数据长度
**  输出参数:  无
**  返回参数:  成功返回TRUE,失败返回FALSE
**************************************************************************************************/
BOOLEAN DAL_Flash_WriteData(INT32U addr, INT8U *data, INT32U dlen)
{
    INT16U                  temp;
    INT32U                  i;
    INT16U       volatile  *paddr;
    FLASH_Status volatile   status;

    status = FLASH_COMPLETE;
        
    if (addr + dlen > ADDR_FLSH_END) {
        return FALSE;
    }
    
    if ((addr % 2) != 0) {
        return FALSE;
    }
    
    if ((dlen % 2) != 0) {
        return FALSE;
    }
    
    paddr = (volatile INT16U *)(addr);
    dlen = dlen / 2;
    
    status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
    
    if (status == FLASH_COMPLETE) {
        
        FLASH->CR |= FLASH_CR_PG;
        
        for (i = 0; i < dlen; i++) {
            temp = data[i * 2] + (data[i * 2 + 1] << 8);
            *paddr++ = temp;
        }
        
        status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
        
        if (status != FLASH_COMPLETE) {
            FLASH->CR &= ~FLASH_CR_PG;
            return FALSE;
        }
        
        FLASH->CR &= ~FLASH_CR_PG;
        
    } else {
        return FALSE;
    }
    
    paddr = (volatile INT16U *)(addr);                                         /* 检查写入数据是否成功 */
    
    for (i = 0; i < dlen; i++) {
        
        temp = data[i * 2] + (data[i * 2 + 1] << 8);
        
        if (paddr[i] != temp) {
            return FALSE;
        }
    }
    
    return true;
}

/**************************************************************************************************
**  函数名称:  DAL_Flash_ReadData
**  功能描述:  读取FLASH内容
**  输入参数:  addr: 读取的地址, 绝对地址，2的整数倍，从0开始; dbuf: 存放读出来的数据; dlen: 数据长度
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
INT32U DAL_Flash_ReadData(INT32U addr, INT8U *dbuf, INT32U dlen)
{
    return FLASH_Read(addr, dbuf, dlen);
}

/**************************************************************************************************
**  函数名称:  DAL_Flash_GetAddrByPage
**  功能描述:  根据扇区号计算扇区的地址
**  输入参数:  page: 扇区号; start: 计算该扇区的起始地址还是结束地址
**  输出参数:  无
**  返回参数:  无
**************************************************************************************************/
INT32U DAL_Flash_GetAddrByPage(INT8U page, BOOLEAN start)
{
    INT32U addr;
    
    if (page >= PAGE_MAX_PAGE) {
        return 0;
    }
    
    if (start == TRUE) {                                                       /* 计算扇区的起始地址 */
        addr = ADDR_FLSH_BGN + (SIZE_PER_PAGE * page);
    } else {                                                                   /* 计算扇区的结束地址 */
        addr = ADDR_FLSH_BGN + (SIZE_PER_PAGE * (page + 1));
    }
    
    return addr;
}

